﻿using OneOf;
using TUnit.TestProject.Attributes;

namespace TUnit.TestProject;

[EngineTest(ExpectedResult.Pass)]
public class MatrixTests
{
    [Test]
    [MatrixDataSource]
    public async Task MatrixTest_One(
        [Matrix("A", "B", "C", "D")] string str,
        [Matrix(1, 2, 3)] int i,
        [Matrix(true, false)] bool boolean)
    {
        await Task.CompletedTask;
    }

    [Test]
    [MatrixDataSource]
    public async Task MatrixTest_Two(
        [Matrix(1, 2)] int i,
        [Matrix(1, 2, 3)] int i2,
        [Matrix(1, 2, 3, 4)] int i3,
        [Matrix(true, false)] bool boolean)
    {
        await Task.CompletedTask;
    }

    [Test]
    [MatrixDataSource]
    public async Task MatrixTest_Enum(
        [Matrix(1, 2)] int i,
        [Matrix(-1, TestEnum.One)] TestEnum testEnum,
        TestEnum? testEnum2)
    {
        await Task.CompletedTask;
    }

    [Test]
    [MatrixDataSource]
    public async Task AutoGenerateBools(
        [Matrix("A", "B", "C")] string str,
        bool boolean)
    {
        await Task.CompletedTask;
    }

    [Test]
    [MatrixDataSource]
    public async Task AutoGenerateBools2(
        [Matrix("A", "B", "C")] string str,
        [Matrix] bool? boolean)
    {
        await Task.CompletedTask;
    }

    [Test]
    [MatrixDataSource]
    public async Task ImplicitConversion(
        [Matrix(TestEnum.One, TestEnum2.Two)] OneOf<TestEnum, TestEnum2> @enum,
        [Matrix] bool boolean)
    {
        await Task.CompletedTask;
    }

    [Test]
    [MatrixDataSource]
    public async Task ExcludingAutoGeneratedMatrixValues(
        [Matrix<CountToTenEnum>(Excluding = [CountToTenEnum.Three, CountToTenEnum.Seven])] CountToTenEnum @enum,
        [Matrix] bool boolean)
    {
        await Assert.That(@enum).IsNotEqualTo(CountToTenEnum.Three)
            .And
            .IsNotEqualTo(CountToTenEnum.Seven);
    }

#if NET7_0_OR_GREATER
        [Test]
        [MatrixDataSource]
        public async Task Range(
            [MatrixRange<int>(-50, 50)] int item)
        {
            await Task.CompletedTask;
        }    
        
        [Test]
        [MatrixDataSource]
        public async Task RangeSteps(
            [MatrixRange<int>(-50, 50, 5)] int item)
        {
            await Task.CompletedTask;
        }

        [Test]
        [MatrixDataSource]
        [MatrixExclusion(3)]
        [MatrixExclusion(7)]
        public async Task Range_Exclusion([MatrixRange<int>(1, 10)] int item)
        {
            await Assert.That(item).IsNotEqualTo(3)
                .And
                .IsNotEqualTo(7);
        }
        
        [Test]
        [MatrixDataSource]
        public async Task Range_Exclusion2([MatrixRange<int>(1, 10, Excluding = [3, 7])] int item)
        {
            await Assert.That(item).IsNotEqualTo(3)
                .And
                .IsNotEqualTo(7);
        }
#endif

    [Test]
    [MatrixDataSource]
    public async Task Method1(
        [MatrixMethod<MatrixTests>(nameof(EnumerableMethod))] int item)
    {
        await Task.CompletedTask;
    }

    [Test]
    [MatrixDataSource]
    public async Task Method2(
        [MatrixMethod<MatrixTests>(nameof(ArrayMethod))] int item)
    {
        await Task.CompletedTask;
    }

    [Test]
    [MatrixDataSource]
    public async Task Method3(
        [MatrixMethod<MatrixTests>(nameof(IntMethod))] int item)
    {
        await Task.CompletedTask;
    }

    [Test]
    [MatrixDataSource]
    public async Task Method4(
        [MatrixMethod<MatrixTests>(nameof(ObjectMethod))] int item)
    {
        await Task.CompletedTask;
    }

    [Test]
    [MatrixDataSource]
    [MatrixExclusion(1, 1)]
    [MatrixExclusion(2, 2)]
    [MatrixExclusion(3, 3)]
    public async Task Exclusion(
        [MatrixMethod<MatrixTests>(nameof(EnumerableMethod))] int item,
        [MatrixMethod<MatrixTests>(nameof(EnumerableMethod))] int item2)
    {
        await Assert.That(item).IsNotEqualTo(item2);
    }

    public enum CountToTenEnum
    {
        One,
        Two,
        Three,
        Four,
        Five,
        Six,
        Seven,
        Eight,
        Nine,
        Ten
    }

    public static IEnumerable<int> EnumerableMethod()
    {
        yield return 1;
        yield return 2;
        yield return 3;
    }

    public static object?[] ArrayMethod()
    {
        return [1, 2, 3];
    }

    public static int IntMethod()
    {
        return 1;
    }

    public static object ObjectMethod()
    {
        return 1;
    }
}
